home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Rozne / HTTrack 3.40-2 / httrack-3.40-2.exe / {app} / src / proxy / store.c < prev    next >
C/C++ Source or Header  |  2006-04-09  |  45KB  |  1,506 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20. Please visit our Website: http://www.httrack.com
  21. */
  22.  
  23. /* ------------------------------------------------------------ */
  24. /* File: Cache manager for ProxyTrack                           */
  25. /* Author: Xavier Roche                                         */
  26. /* ------------------------------------------------------------ */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31.  
  32. /* Locking */
  33. #ifdef _WIN32
  34. #include <process.h>    /* _beginthread, _endthread */
  35. #else
  36. #include <pthread.h>
  37. #endif
  38.  
  39. #include "htsglobal.h"
  40.  
  41. #define HTS_INTERNAL_BYTECODE
  42. #include "htsinthash.h"
  43. #undef HTS_INTERNAL_BYTECODE
  44. #include "../minizip/mztools.h"
  45.  
  46. #include "htscore.h"
  47. #include "htsback.h"
  48.  
  49. #include "store.h"
  50. #include "proxystrings.h"
  51. #include "proxytrack.h"
  52.  
  53. /* Unlocked functions */
  54.  
  55. static int PT_LookupCache__New_u(PT_Index index, const char* url);
  56. static PT_Element PT_ReadCache__New_u(PT_Index index, const char* url, int flags);
  57.  
  58. static int PT_LookupCache__Old_u(PT_Index index, const char* url);
  59. static PT_Element PT_ReadCache__Old_u(PT_Index index, const char* url, int flags);
  60.  
  61.  
  62. /* Locking */
  63.  
  64. #ifdef _WIN32
  65. void MutexInit(PT_Mutex *pMutex) {
  66.     *pMutex = CreateMutex(NULL,FALSE,NULL);
  67. }
  68.  
  69. void MutexLock(PT_Mutex *pMutex) {
  70.     WaitForSingleObject(*pMutex, INFINITE);
  71. }
  72.  
  73. void MutexUnlock(PT_Mutex *pMutex) {
  74.     ReleaseMutex(*pMutex);
  75. }
  76.  
  77. void MutexFree(PT_Mutex *pMutex) {
  78.     CloseHandle(*pMutex);
  79.     *pMutex = NULL;
  80. }
  81. #else
  82. void MutexInit(PT_Mutex *pMutex) {
  83.     (void) pthread_mutex_init(pMutex, 0);
  84. }
  85.  
  86. void MutexLock(PT_Mutex *pMutex) {
  87.     pthread_mutex_lock(pMutex);
  88. }
  89.  
  90. void MutexUnlock(PT_Mutex *pMutex) {
  91.     pthread_mutex_unlock(pMutex);
  92. }
  93.  
  94. void MutexFree(PT_Mutex *pMutex) {
  95.     pthread_mutex_destroy(pMutex);
  96. }
  97. #endif
  98.  
  99. /* Indexes */
  100.  
  101. typedef struct _PT_Index__New _PT_Index__New;
  102. typedef struct _PT_Index__Old _PT_Index__Old;
  103. typedef struct _PT_Index_Functions _PT_Index_Functions;
  104.  
  105. typedef struct _PT_Index__New *PT_Index__New;
  106. typedef struct _PT_Index__Old *PT_Index__Old;
  107. typedef struct _PT_Index_Functions *PT_Index_Functions;
  108.  
  109. enum {
  110.     PT_CACHE_UNDEFINED = -1,
  111.     PT_CACHE_MIN = 0,
  112.     PT_CACHE__NEW = PT_CACHE_MIN,
  113.     PT_CACHE__OLD,
  114.     PT_CACHE_MAX = PT_CACHE__OLD
  115. };
  116.  
  117. static int PT_LoadCache__New(PT_Index index, const char *filename);
  118. static void PT_Index_Delete__New(PT_Index *pindex);
  119. static PT_Element PT_ReadCache__New(PT_Index index, const char* url, int flags);
  120. static int PT_LookupCache__New(PT_Index index, const char* url);
  121. /**/
  122. static int PT_LoadCache__Old(PT_Index index, const char *filename);
  123. static void PT_Index_Delete__Old(PT_Index *pindex);
  124. static PT_Element PT_ReadCache__Old(PT_Index index, const char* url, int flags);
  125. static int PT_LookupCache__Old(PT_Index index, const char* url);
  126.  
  127. struct _PT_Index_Functions {
  128.     int (*PT_LoadCache)(PT_Index index, const char *filename);
  129.     void (*PT_Index_Delete)(PT_Index *pindex);
  130.     PT_Element (*PT_ReadCache)(PT_Index index, const char* url, int flags);
  131.     int (*PT_LookupCache)(PT_Index index, const char* url);
  132. };
  133.  
  134. static _PT_Index_Functions _IndexFuncts[] = {
  135.   { PT_LoadCache__New, PT_Index_Delete__New, PT_ReadCache__New, PT_LookupCache__New },
  136.   { PT_LoadCache__Old, PT_Index_Delete__Old, PT_ReadCache__Old, PT_LookupCache__Old },
  137.     { NULL, NULL, NULL, NULL }
  138. };
  139.  
  140. #define PT_INDEX_COMMON_STRUCTURE \
  141.     time_t timestamp;                                \
  142.     inthash hash;                                        \
  143.     char startUrl[1024]
  144.  
  145. struct _PT_Index__New {
  146.     PT_INDEX_COMMON_STRUCTURE;
  147.     char path[1024];        /* either empty, or must include ending / */
  148.     int fixedPath;
  149.     int safeCache;
  150.     unzFile zFile;
  151.     PT_Mutex zFileLock;
  152. };
  153.  
  154. struct _PT_Index__Old {
  155.     PT_INDEX_COMMON_STRUCTURE;
  156.     char filenameDat[1024];
  157.     char filenameNdx[1024];
  158.     FILE *dat,*ndx;
  159.     PT_Mutex fileLock;
  160.     int version;
  161.     char lastmodified[1024];
  162.     char path[1024];        /* either empty, or must include ending / */
  163.     int fixedPath;
  164.     int safeCache;
  165. };
  166.  
  167. struct _PT_Index {
  168.     int type;
  169.     union {
  170.         _PT_Index__New formatNew;
  171.         _PT_Index__Old formatOld;
  172.         struct {
  173.             PT_INDEX_COMMON_STRUCTURE;
  174.         } common;
  175.     } slots;
  176. };
  177.  
  178. struct _PT_Indexes {
  179.     inthash cil;
  180.     struct _PT_Index **index;
  181.     int index_size;
  182. };
  183.  
  184. struct _PT_CacheItem {
  185.     time_t lastUsed;
  186.     size_t size;
  187.     void* data;
  188. };
  189.  
  190. struct _PT_Cache {
  191.     inthash index;
  192.     size_t maxSize;
  193.     size_t totalSize;
  194.     int count;
  195. };
  196.  
  197. PT_Indexes PT_New() {
  198.     PT_Indexes index = (PT_Indexes) calloc(sizeof(_PT_Indexes), 1);
  199.     index->cil = inthash_new(127);
  200.     index->index_size = 0;
  201.     index->index = NULL;
  202.     return index;
  203. }
  204.  
  205. void PT_Delete(PT_Indexes index) {
  206.     if (index != NULL) {
  207.         inthash_delete(&index->cil);
  208.         free(index);
  209.     }
  210. }
  211.  
  212. int PT_RemoveIndex(PT_Indexes index, int indexId) {
  213.     return 0;
  214. }
  215.  
  216. #define assertf(exp)
  217.  
  218. static int binput(char* buff,char* s,int max) {
  219.   int count = 0;
  220.   int destCount = 0;
  221.  
  222.   // Note: \0 will return 1
  223.   while(destCount < max && buff[count] != '\0' && buff[count] != '\n') {
  224.     if (buff[count] != '\r') {
  225.       s[destCount++] = buff[count];
  226.     }
  227.         count++;
  228.   }
  229.   s[destCount] = '\0';
  230.  
  231.   // then return the supplemental jump offset
  232.   return count + 1;
  233. }
  234.  
  235. static time_t file_timestamp(const char* file) {
  236.   struct stat buf;
  237.   if (stat(file, &buf) == 0) {
  238.     time_t tt = buf.st_mtime;
  239.         if (tt != (time_t) 0 && tt != (time_t) -1) {
  240.             return tt;
  241.         }
  242.   }
  243.   return (time_t) 0;
  244. }
  245.  
  246. static int PT_Index_Check__(PT_Index index, const char* file, int line) {
  247.     if (index == NULL)
  248.         return 0;
  249.     if (index->type >= PT_CACHE_MIN && index->type <= PT_CACHE_MAX)
  250.         return 1;
  251.     CRITICAL_("index corrupted in memory", file, line);
  252.     return 0;
  253. }
  254. #define SAFE_INDEX(index) PT_Index_Check__(index, __FILE__, __LINE__)
  255.  
  256.  
  257. /* ------------------------------------------------------------ */
  258. /* Generic cache dispatch                                       */
  259. /* ------------------------------------------------------------ */
  260.  
  261. void PT_Index_Delete(PT_Index *pindex) {
  262.     if (pindex != NULL && (*pindex) != NULL) {
  263.         PT_Index index = *pindex;
  264.         if (SAFE_INDEX(index)) {
  265.             _IndexFuncts[index->type].PT_Index_Delete(pindex);
  266.         }
  267.         free(index);
  268.         *pindex = NULL;
  269.     }
  270. }
  271.  
  272. static void PT_Index_Delete__New(PT_Index *pindex) {
  273.     if (pindex != NULL && (*pindex) != NULL) {
  274.         PT_Index__New index = &(*pindex)->slots.formatNew;
  275.         if (index->zFile != NULL) {
  276.             unzClose(index->zFile);
  277.             index->zFile = NULL;
  278.         }
  279.         if (index->hash != NULL) {
  280.             inthash_delete(&index->hash);
  281.             index->hash = NULL;
  282.         }
  283.         MutexFree(&index->zFileLock);
  284.     }
  285. }
  286.  
  287. static void PT_Index_Delete__Old(PT_Index *pindex) {
  288.     if (pindex != NULL && (*pindex) != NULL) {
  289.         PT_Index__Old index = &(*pindex)->slots.formatOld;
  290.         if (index->dat != NULL) {
  291.             fclose(index->dat);
  292.         }
  293.         if (index->ndx != NULL) {
  294.             fclose(index->ndx);
  295.         }
  296.         if (index->hash != NULL) {
  297.             inthash_delete(&index->hash);
  298.             index->hash = NULL;
  299.         }
  300.         MutexFree(&index->fileLock);
  301.     }
  302. }
  303.  
  304. int PT_AddIndex(PT_Indexes indexes, const char *path) {
  305.     PT_Index index = PT_LoadCache(path);
  306.     if (index != NULL) {
  307.         int ret = PT_IndexMerge(indexes, &index);
  308.         if (index != NULL) {
  309.             PT_Index_Delete(&index);
  310.         }
  311.         return ret;
  312.     }
  313.     return -1;
  314. }
  315.  
  316. PT_Element PT_Index_HTML_BuildRootInfo(PT_Indexes indexes) {
  317.     if (indexes != NULL) {
  318.         PT_Element elt = PT_ElementNew();
  319.         int i;
  320.         String html = STRING_EMPTY;
  321.         StringClear(html);
  322.         StringStrcat(html, 
  323.             "<html>"
  324.             PROXYTRACK_COMMENT_HEADER
  325.             DISABLE_IE_FRIENDLY_HTTP_ERROR_MESSAGES
  326.             "<head>\r\n"
  327.             "<title>ProxyTrack " PROXYTRACK_VERSION " Catalog</title>"
  328.             "</head>\r\n"
  329.             "<body>\r\n"
  330.             "<h3>Available sites in this cache:</h3><br />"
  331.             "<br />"
  332.             );
  333.         StringStrcat(html, "<ul>\r\n");
  334.         for(i = 0 ; i < indexes->index_size ; i++) {
  335.             if (indexes->index[i] != NULL
  336.                 && indexes->index[i]->slots.common.startUrl[0] != '\0')
  337.             {
  338.                 const char * url = indexes->index[i]->slots.common.startUrl;
  339.                 StringStrcat(html, "<li>\r\n");
  340.                 StringStrcat(html, "<a href=\"");
  341.                 StringStrcat(html, url);
  342.                 StringStrcat(html, "\">");
  343.                 StringStrcat(html, url);
  344.                 StringStrcat(html, "</a>\r\n");
  345.                 StringStrcat(html, "</li>\r\n");
  346.             }
  347.         }
  348.         StringStrcat(html, "</ul>\r\n");
  349.         StringStrcat(html, "</body></html>\r\n");
  350.         elt->size = StringLength(html);
  351.         elt->adr = StringAcquire(&html);
  352.         elt->statuscode = 200;
  353.         strcpy(elt->charset, "iso-8859-1");
  354.         strcpy(elt->contenttype, "text/html");
  355.         strcpy(elt->msg, "OK");
  356.         StringFree(html);
  357.         return elt;
  358.     }
  359.     return NULL;
  360. }
  361.  
  362. static char* strchr_stop(char* str, char c, char stop) {
  363.     for( ; *str != 0 && *str != stop && *str != c ; str++);
  364.     if (*str == c)
  365.         return str;
  366.     return NULL;
  367. }
  368.  
  369. char ** PT_Enumerate(PT_Indexes indexes, const char *url, int subtree) {
  370.     // should be cached!
  371.     if (indexes != NULL && indexes->cil != NULL) {
  372.         unsigned int urlSize;
  373.         String list = STRING_EMPTY;
  374.         String listindexes = STRING_EMPTY;
  375.         String subitem = STRING_EMPTY;
  376.         unsigned int listCount = 0;
  377.         struct_inthash_enum en = inthash_enum_new(indexes->cil);
  378.         inthash_chain* chain;
  379.         inthash hdupes = NULL;
  380.         if (!subtree)
  381.             hdupes= inthash_new(127);
  382.         StringClear(list);
  383.         StringClear(listindexes);
  384.         StringClear(subitem);
  385.         if (strncmp(url, "http://", 7) == 0)
  386.             url += 7;
  387.         urlSize = (unsigned int) strlen(url);
  388.         while((chain = inthash_enum_next(&en))) {
  389.             long int index = (long int)chain->value.intg;
  390.             if (urlSize == 0 || strncmp(chain->name, url, urlSize) == 0) {
  391.                 if (index >= 0 && index < indexes->index_size) {
  392.                     char * item = chain->name + urlSize;
  393.                     if (*item == '/')
  394.                         item++;
  395.                     {
  396.                         char * pos = subtree ? 0 : strchr_stop(item, '/', '?');
  397.                         unsigned int len = pos ? (unsigned int)( pos - item ) : (unsigned int)strlen(item);
  398.                         if (len > 0 /* default document */ || *item == 0) {
  399.                             int isFolder = ( item[len] == '/' );
  400.                             StringClear(subitem);
  401.                             if (len > 0)
  402.                                 StringMemcat(subitem, item, len);
  403.                             if (len == 0 || !inthash_exists(hdupes, StringBuff(subitem))) {
  404.                                 char* ptr = NULL;
  405.                                 ptr += StringLength(list);
  406.                                 if (len > 0)
  407.                                     StringStrcat(list, StringBuff(subitem));
  408.                                 if (isFolder)
  409.                                     StringStrcat(list, "/");
  410.                                 StringMemcat(list, "\0", 1);        /* NULL terminated strings */
  411.                                 StringMemcat(listindexes, &ptr, sizeof(ptr));
  412.                                 listCount++;
  413.                                 inthash_write(hdupes, StringBuff(subitem), 0);
  414.                             }
  415.                         }
  416.                     }
  417.                 } else {
  418.                     CRITICAL("PT_Enumerate:Corrupted central index locator");
  419.                 }
  420.             }
  421.         }
  422.         StringFree(subitem);
  423.         inthash_delete(&hdupes);
  424.         if (listCount > 0) {
  425.             unsigned int i;
  426.             void* blk;
  427.             char *nullPointer = NULL;
  428.             char* startStrings;
  429.             /* NULL terminated index */
  430.             StringMemcat(listindexes, &nullPointer, sizeof(nullPointer));
  431.             /* start of all strings (index) */
  432.             startStrings = nullPointer + StringLength(listindexes);
  433.             /* copy list of URLs after indexes */
  434.             StringMemcat(listindexes, StringBuff(list), StringLength(list));
  435.             /* ---- no reallocation beyond this point (fixed addresses) ---- */
  436.             /* start of all strings (pointer) */
  437.             startStrings = (startStrings - nullPointer) + StringBuff(listindexes);
  438.             /* transform indexes into references */
  439.             for(i = 0 ; i < listCount ; i++) {
  440.                 char *ptr = NULL;
  441.                 unsigned int ndx;
  442.                 memcpy(&ptr, &StringBuff(listindexes)[i*sizeof(char*)], sizeof(char*));
  443.                 ndx = (unsigned int) (ptr - nullPointer);
  444.                 ptr = startStrings + ndx;
  445.                 memcpy(&StringBuff(listindexes)[i*sizeof(char*)], &ptr, sizeof(char*));
  446.             }
  447.             blk = StringAcquire(&listindexes);
  448.             StringFree(list);
  449.             StringFree(listindexes);
  450.             return (char **)blk;
  451.         }
  452.     }
  453.     return NULL;
  454. }
  455.  
  456. void PT_Enumerate_Delete(char ***plist) {
  457.     if (plist != NULL && *plist != NULL) {
  458.         free(*plist);
  459.         *plist = NULL;
  460.     }
  461. }
  462.  
  463. PT_Index PT_LoadCache(const char *filename) {
  464.     int type = PT_CACHE_UNDEFINED;
  465.     char * dot = strrchr(filename, '.');
  466.     if (dot != NULL) {
  467.         if (strcasecmp(dot, ".zip") == 0) {
  468.             type = PT_CACHE__NEW;
  469.         } else if (strcasecmp(dot, ".ndx") == 0 || strcasecmp(dot, ".dat") == 0) {
  470.             type = PT_CACHE__OLD;
  471.         }
  472.     }
  473.     if (type != PT_CACHE_UNDEFINED) {
  474.         PT_Index index = calloc(sizeof(_PT_Index), 1);
  475.         if (index != NULL) {
  476.             index->type = type;
  477.             index->slots.common.timestamp = (time_t) time(NULL);
  478.             index->slots.common.startUrl[0] = '\0';
  479.             index->slots.common.hash = inthash_new(8191);
  480.             if (!_IndexFuncts[type].PT_LoadCache(index, filename)) {
  481.                 DEBUG("reading httrack cache (format #%d) %s : error" _ type _ filename );
  482.                 free(index);
  483.                 index = NULL;
  484.                 return NULL;
  485.             } else {
  486.                 DEBUG("reading httrack cache (format #%d) %s : success" _ type _ filename );
  487.             }
  488.             /* default starting URL is the first hash entry */
  489.             if (index->slots.common.startUrl[0] == '\0') {
  490.                 struct_inthash_enum en = inthash_enum_new(index->slots.common.hash);
  491.                 inthash_chain* chain;
  492.                 chain = inthash_enum_next(&en);
  493.                 if (chain != NULL
  494.                     && strstr(chain->name, "/robots.txt") != NULL) 
  495.                 {
  496.                     chain = inthash_enum_next(&en);
  497.                 }
  498.                 if (chain != NULL) {
  499.                     if (!link_has_authority(chain->name))
  500.                         strcat(index->slots.common.startUrl, "http://");
  501.                     strcat(index->slots.common.startUrl, chain->name);
  502.                 }
  503.             }
  504.         }
  505.         return index;
  506.     }
  507.     return NULL;
  508. }
  509.  
  510.  
  511. static long int filesize(const char* filename) {
  512.   struct stat st;
  513.   memset(&st, 0, sizeof(st));
  514.   if (stat(filename, &st) == 0) {
  515.         return (long int)st.st_size;
  516.   }
  517.   return -1;
  518.  
  519. int PT_LookupCache(PT_Index index, const char* url) {
  520.     if (index != NULL && SAFE_INDEX(index)) {
  521.         return _IndexFuncts[index->type].PT_LookupCache(index, url);
  522.     }
  523.     return 0;
  524. }
  525.  
  526. time_t PT_Index_Timestamp(PT_Index index) {
  527.     return index->slots.common.timestamp;
  528. }
  529.  
  530. static int PT_LookupCache__New(PT_Index index, const char* url) {
  531.     int retCode;
  532.     MutexLock(&index->slots.formatNew.zFileLock);
  533.     {
  534.         retCode = PT_LookupCache__New_u(index, url);
  535.     }
  536.     MutexUnlock(&index->slots.formatNew.zFileLock);
  537.     return retCode;
  538. }
  539.  
  540. static int PT_LookupCache__New_u(PT_Index index_, const char* url) {
  541.     if (index_ != NULL) {
  542.         PT_Index__New index = &index_->slots.formatNew;
  543.         if (index->hash != NULL && index->zFile != NULL && url != NULL && *url != 0) {
  544.             int hash_pos_return;
  545.             if (strncmp(url, "http://", 7) == 0)
  546.                 url += 7;
  547.             hash_pos_return = inthash_read(index->hash, url, NULL);
  548.             if (hash_pos_return)
  549.                 return 1;
  550.         }
  551.     }
  552.     return 0;
  553. }
  554.  
  555. int PT_IndexMerge(PT_Indexes indexes, PT_Index *pindex)
  556. {
  557.     if (pindex != NULL && *pindex != NULL && (*pindex)->slots.common.hash != NULL
  558.         && indexes != NULL) 
  559.     {
  560.         PT_Index index = *pindex;
  561.         struct_inthash_enum en = inthash_enum_new(index->slots.common.hash);
  562.         inthash_chain* chain;
  563.         int index_id = indexes->index_size++;
  564.         int nMerged = 0;
  565.         if ((indexes->index = realloc(indexes->index, sizeof(struct _PT_Index)*indexes->index_size)) != NULL) {
  566.             indexes->index[index_id] = index;
  567.             *pindex = NULL;
  568.             while((chain = inthash_enum_next(&en)) != NULL) {
  569.                 const char * url = chain->name;
  570.                 if (url != NULL && url[0] != '\0') {
  571.                     long int previous_index_id = 0;
  572.                     if (inthash_read(indexes->cil, url, (long int*)&previous_index_id)) {
  573.                         if (previous_index_id >= 0 && previous_index_id < indexes->index_size) {
  574.                             if (indexes->index[previous_index_id]->slots.common.timestamp > index->slots.common.timestamp)            // existing entry is newer
  575.                                 break;
  576.                         } else {
  577.                             CRITICAL("PT_IndexMerge:Corrupted central index locator");
  578.                         }
  579.                     }
  580.                     inthash_write(indexes->cil, chain->name, index_id);
  581.                     nMerged++;
  582.                 }
  583.             }
  584.         } else {
  585.             CRITICAL("PT_IndexMerge:Memory exhausted");
  586.         }
  587.         return nMerged;
  588.     }
  589.     return -1;
  590. }
  591.  
  592. void PT_Element_Delete(PT_Element *pentry) {
  593.     if (pentry != NULL) {
  594.         PT_Element entry = *pentry;
  595.         if (entry != NULL) {
  596.             if (entry->adr != NULL) {
  597.                 free(entry->adr);
  598.                 entry->adr = NULL;
  599.             }
  600.             if (entry->headers != NULL) {
  601.                 free(entry->headers);
  602.                 entry->headers = NULL;
  603.             }
  604.             if (entry->location != NULL) {
  605.                 free(entry->location);
  606.                 entry->location = NULL;
  607.             }
  608.             free(entry);
  609.         }
  610.         *pentry = NULL;
  611.     }
  612. }
  613.  
  614. PT_Element PT_ReadIndex(PT_Indexes indexes, const char* url, int flags)
  615. {
  616.     if (indexes != NULL) 
  617.     {
  618.         long int index_id;
  619.         if (strncmp(url, "http://", 7) == 0)
  620.             url += 7;
  621.         if (inthash_read(indexes->cil, url, &index_id)) {
  622.             if (index_id >= 0 && index_id <= indexes->index_size) {
  623.                 PT_Element item =  PT_ReadCache(indexes->index[index_id], url, flags);
  624.                 if (item != NULL) {
  625.                     item->indexId = index_id;
  626.                     return item;
  627.                 }
  628.             } else {
  629.                 CRITICAL("PT_ReadCache:Corrupted central index locator");
  630.             }
  631.         }
  632.     }
  633.     return NULL;
  634. }
  635.  
  636. int PT_LookupIndex(PT_Indexes indexes, const char* url) {
  637.     if (indexes != NULL) 
  638.     {
  639.         long int index_id;
  640.         if (strncmp(url, "http://", 7) == 0)
  641.             url += 7;
  642.         if (inthash_read(indexes->cil, url, &index_id)) {
  643.             if (index_id >= 0 && index_id <= indexes->index_size) {
  644.                 return 1;
  645.             } else {
  646.                 CRITICAL("PT_ReadCache:Corrupted central index locator");
  647.             }
  648.         }
  649.     }
  650.     return 0;
  651. }
  652.  
  653. PT_Index PT_GetIndex(PT_Indexes indexes, int indexId) {
  654.     if (indexes != NULL && indexId >= 0 && indexId < indexes->index_size) 
  655.     {
  656.         return indexes->index[indexId];
  657.     }
  658.     return NULL;
  659. }
  660.  
  661. PT_Element PT_ElementNew() {
  662.     PT_Element r = NULL;
  663.     if ((r = calloc(sizeof(_PT_Element), 1)) == NULL)
  664.         return NULL;
  665.     r->statuscode=STATUSCODE_INVALID;
  666.     r->indexId = -1;
  667.     return r;
  668. }
  669.  
  670. PT_Element PT_ReadCache(PT_Index index, const char* url, int flags) {
  671.     if (index != NULL && SAFE_INDEX(index)) {
  672.         return _IndexFuncts[index->type].PT_ReadCache(index, url, flags);
  673.     }
  674.     return NULL;
  675. }
  676.  
  677. static PT_Element PT_ReadCache__New(PT_Index index, const char* url, int flags) {
  678.     PT_Element retCode;
  679.     MutexLock(&index->slots.formatNew.zFileLock);
  680.     {
  681.         retCode = PT_ReadCache__New_u(index, url, flags);
  682.     }
  683.     MutexUnlock(&index->slots.formatNew.zFileLock);
  684.     return retCode;
  685. }
  686.  
  687.  
  688. /* ------------------------------------------------------------ */
  689. /* New HTTrack cache (new.zip) format                           */
  690. /* ------------------------------------------------------------ */
  691.  
  692. #define ZIP_READFIELD_STRING(line, value, refline, refvalue) do { \
  693.   if (line[0] != '\0' && strfield2(line, refline)) { \
  694.     strcpy(refvalue, value); \
  695.     line[0] = '\0'; \
  696.     } \
  697. } while(0)
  698. #define ZIP_READFIELD_INT(line, value, refline, refvalue) do { \
  699.   if (line[0] != '\0' && strfield2(line, refline)) { \
  700.     int intval = 0; \
  701.     sscanf(value, "%d", &intval); \
  702.     (refvalue) = intval; \
  703.     line[0] = '\0'; \
  704.     } \
  705. } while(0)
  706.  
  707. int PT_LoadCache__New(PT_Index index_, const char *filename) {
  708.     if (index_ != NULL && filename != NULL) {
  709.         PT_Index__New index = &index_->slots.formatNew;
  710.         unzFile zFile = index->zFile = unzOpen(filename);
  711.         index->timestamp = file_timestamp(filename);
  712.         MutexInit(&index->zFileLock);
  713.  
  714.         // Opened ?
  715.         if (zFile!=NULL) {
  716.             const char * abpath;
  717.             int slashes;
  718.             inthash hashtable = index->hash;
  719.  
  720.             /* Compute base path for this index - the filename MUST be absolute! */
  721.             for(slashes = 2, abpath = filename + (int)strlen(filename) - 1 
  722.                 ; abpath > filename && ( ( *abpath != '/'&& *abpath != '\\' ) || --slashes > 0)
  723.                 ; abpath--);
  724.             index->path[0] = '\0';
  725.             if (slashes == 0 && *abpath != 0) {
  726.                 int i;
  727.                 strncat(index->path, filename, (int) ( abpath - filename ) + 1 );
  728.                 for(i = 0 ; index->path[i] != 0 ; i++) {
  729.                     if (index->path[i] == '\\') {
  730.                         index->path[i] = '/';
  731.                     }
  732.                 }
  733.             }
  734.  
  735.             /* Ready directory entries */
  736.             if (unzGoToFirstFile(zFile) == Z_OK) {
  737.                 char comment[128];
  738.                 char filename[HTS_URLMAXSIZE * 4];
  739.                 int entries = 0;
  740.                 int firstSeen = 0;
  741.                 memset(comment, 0, sizeof(comment));       // for truncated reads
  742.                 do  {
  743.                     int readSizeHeader = 0;
  744.                     filename[0] = '\0';
  745.                     comment[0] = '\0';
  746.                     if (unzOpenCurrentFile(zFile) == Z_OK) {
  747.                         if (
  748.                             (readSizeHeader = unzGetLocalExtrafield(zFile, comment, sizeof(comment) - 2)) > 0
  749.                             &&
  750.                             unzGetCurrentFileInfo(zFile, NULL, filename, sizeof(filename) - 2, NULL, 0, NULL, 0) == Z_OK
  751.                             ) 
  752.                         {
  753.                             long int pos = (long int) unzGetOffset(zFile);
  754.                             assertf(readSizeHeader < sizeof(comment));
  755.                             comment[readSizeHeader] = '\0';
  756.                             entries++;
  757.                             if (pos > 0) {
  758.                                 int dataincache = 0;    // data in cache ?
  759.                                 char* filenameIndex = filename;
  760.                                 if (strncmp(filenameIndex, "http://", 7) == 0) {
  761.                                     filenameIndex += 7;
  762.                                 }
  763.                                 if (comment[0] != '\0') {
  764.                                     int maxLine = 2;
  765.                                     char* a = comment;
  766.                                     while(*a && maxLine-- > 0) {      // parse only few first lines
  767.                                         char line[1024];
  768.                                         line[0] = '\0';
  769.                                         a+=binput(a, line, sizeof(line) - 2);
  770.                                         if (strncmp(line, "X-In-Cache:", 11) == 0) {
  771.                                             if (strcmp(line, "X-In-Cache: 1") == 0) {
  772.                                                 dataincache = 1;
  773.                                             } else {
  774.                                                 dataincache = 0;
  775.                                             }
  776.                                             break;
  777.                                         }
  778.                                     }
  779.                                 }
  780.                                 if (dataincache)
  781.                                     inthash_add(hashtable, filenameIndex, pos);
  782.                                 else
  783.                                     inthash_add(hashtable, filenameIndex, -pos);
  784.  
  785.                                 /* First link as starting URL */
  786.                                 if (!firstSeen) {
  787.                                     if (strstr(filenameIndex, "/robots.txt") == NULL) {
  788.                                         firstSeen = 1;
  789.                                         if (!link_has_authority(filenameIndex))
  790.                                             strcat(index->startUrl, "http://");
  791.                                         strcat(index->startUrl, filenameIndex);
  792.                                     }
  793.                                 }
  794.                             } else {
  795.                                 fprintf(stderr, "Corrupted cache meta entry #%d"LF, (int)entries);
  796.                             }
  797.                         } else {
  798.                             fprintf(stderr, "Corrupted cache entry #%d"LF, (int)entries);
  799.                         }
  800.                         unzCloseCurrentFile(zFile);
  801.                     } else {
  802.                         fprintf(stderr, "Corrupted cache entry #%d"LF, (int)entries);
  803.                     }
  804.                 } while( unzGoToNextFile(zFile) == Z_OK );
  805.                 return 1;
  806.             } else {
  807.                 inthash_delete(&index->hash);
  808.                 index = NULL;
  809.             }
  810.         } else {
  811.             index = NULL;
  812.         }
  813.     }
  814.     return 0;
  815. }
  816.  
  817. static PT_Element PT_ReadCache__New_u(PT_Index index_, const char* url, int flags)
  818. {
  819.     PT_Index__New index = (PT_Index__New) &index_->slots.formatNew;
  820.   char location_default[HTS_URLMAXSIZE*2];
  821.   char previous_save[HTS_URLMAXSIZE*2];
  822.   char previous_save_[HTS_URLMAXSIZE*2];
  823.   long int hash_pos;
  824.   int hash_pos_return;
  825.     PT_Element r = NULL;
  826.     if (index == NULL || index->hash == NULL || index->zFile == NULL || url == NULL || *url == 0)
  827.         return NULL;
  828.     if ((r = PT_ElementNew()) == NULL)
  829.         return NULL;
  830.     location_default[0] = '\0';
  831.     previous_save[0] = previous_save_[0] = '\0';
  832.   memset(r, 0, sizeof(_PT_Element));
  833.   r->location = location_default;
  834.     strcpy(r->location, ""); 
  835.     if (strncmp(url, "http://", 7) == 0)
  836.         url += 7;
  837.   hash_pos_return = inthash_read(index->hash, url, (long int*)&hash_pos);
  838.  
  839.   if (hash_pos_return) {
  840.     uLong posInZip;
  841.     if (hash_pos > 0) {
  842.       posInZip = (uLong) hash_pos;
  843.     } else {
  844.       posInZip = (uLong) -hash_pos;
  845.     }
  846.         if (unzSetOffset(index->zFile, posInZip) == Z_OK) {
  847.       /* Read header (Max 8KiB) */
  848.       if (unzOpenCurrentFile(index->zFile) == Z_OK) {
  849.         char headerBuff[8192 + 2];
  850.         int readSizeHeader;
  851.         int totalHeader = 0;
  852.         int dataincache = 0;
  853.         
  854.         /* For BIG comments */
  855.         headerBuff[0] 
  856.           = headerBuff[sizeof(headerBuff) - 1] 
  857.           = headerBuff[sizeof(headerBuff) - 2] 
  858.           = headerBuff[sizeof(headerBuff) - 3] = '\0';
  859.  
  860.         if ( (readSizeHeader = unzGetLocalExtrafield(index->zFile, headerBuff, sizeof(headerBuff) - 2)) > 0) 
  861.         {
  862.           int offset = 0;
  863.           char line[HTS_URLMAXSIZE + 2];
  864.           int lineEof = 0;
  865.           headerBuff[readSizeHeader] = '\0';
  866.           do {
  867.             char* value;
  868.             line[0] = '\0';
  869.             offset += binput(headerBuff + offset, line, sizeof(line) - 2);
  870.             if (line[0] == '\0') {
  871.               lineEof = 1;
  872.             }
  873.             value = strchr(line, ':');
  874.             if (value != NULL) {
  875.               *value++ = '\0';
  876.               if (*value == ' ' || *value == '\t') value++;
  877.               ZIP_READFIELD_INT(line, value, "X-In-Cache", dataincache);
  878.               ZIP_READFIELD_INT(line, value, "X-Statuscode", r->statuscode);
  879.               ZIP_READFIELD_STRING(line, value, "X-StatusMessage", r->msg);              // msg
  880.               ZIP_READFIELD_INT(line, value, "X-Size", r->size);           // size
  881.               ZIP_READFIELD_STRING(line, value, "Content-Type", r->contenttype);      // contenttype
  882.               ZIP_READFIELD_STRING(line, value, "X-Charset", r->charset);          // contenttype
  883.               ZIP_READFIELD_STRING(line, value, "Last-Modified", r->lastmodified);     // last-modified
  884.               ZIP_READFIELD_STRING(line, value, "Etag", r->etag);             // Etag
  885.               ZIP_READFIELD_STRING(line, value, "Location", r->location);         // 'location' pour moved
  886.               ZIP_READFIELD_STRING(line, value, "Content-Disposition", r->cdispo);           // Content-disposition
  887.               //ZIP_READFIELD_STRING(line, value, "X-Addr", ..);            // Original address
  888.               //ZIP_READFIELD_STRING(line, value, "X-Fil", ..);            // Original URI filename
  889.               ZIP_READFIELD_STRING(line, value, "X-Save", previous_save_);           // Original save filename
  890.             }
  891.           } while(offset < readSizeHeader && !lineEof);
  892.           totalHeader = offset;
  893.  
  894.                     /* Previous entry */
  895.                     if (previous_save_[0] != '\0') {
  896.                         int pathLen = (int) strlen(index->path);
  897.                         if (pathLen > 0 && strncmp(previous_save_, index->path, pathLen) == 0) {            // old (<3.40) buggy format
  898.                             strcpy(previous_save, previous_save_);
  899.                         }
  900.                         // relative ? (hack)
  901.                         else if (index->safeCache
  902.                             || (previous_save_[0] != '/'                                                                    // /home/foo/bar.gif
  903.                             && ( !isalpha(previous_save_[0]) || previous_save_[1] != ':' ) )    // c:/home/foo/bar.gif
  904.                             )
  905.                         {
  906.                             index->safeCache = 1;
  907.                             sprintf(previous_save, "%s%s", index->path, previous_save_);
  908.                         }
  909.                         // bogus format (includes buggy absolute path)
  910.                         else {
  911.                             /* guess previous path */
  912.                             if (index->fixedPath == 0) {
  913.                                 const char * start = jump_protocol_and_auth(url);
  914.                                 const char * end = start ? strchr(start, '/') : NULL;
  915.                                 int len = (int) (end - start);
  916.                                 if (start != NULL && end != NULL && len > 0 && len < 128) {
  917.                                     char piece[128 + 2];
  918.                                     const char * where;
  919.                                     piece[0] = '\0';
  920.                                     strncat(piece, start, len);
  921.                                     if ((where = strstr(previous_save_, piece)) != NULL) {
  922.                                         index->fixedPath = (int) (where - previous_save_);        // offset to relative path
  923.                                     }
  924.                                 }
  925.                             }
  926.                             if (index->fixedPath > 0) {
  927.                                 int saveLen = (int) strlen(previous_save_);
  928.                                 if (index->fixedPath < saveLen) {
  929.                                     sprintf(previous_save, "%s%s", index->path, previous_save_ + index->fixedPath);
  930.                                 } else {
  931.                                     sprintf(r->msg, "Bogus fixePath prefix for %s (prefixLen=%d)", previous_save_, (int)index->fixedPath);
  932.                                     r->statuscode = STATUSCODE_INVALID;
  933.                                 }
  934.                             } else {
  935.                                 sprintf(previous_save, "%s%s", index->path, previous_save_);
  936.                             }
  937.                         }
  938.                     }
  939.  
  940.           /* Complete fields */
  941.           r->adr=NULL;
  942.           if (r->statuscode != STATUSCODE_INVALID) {            /* Can continue */
  943.             int ok = 0;
  944.                        
  945.             // Court-circuit:
  946.             // Peut-on stocker le fichier directement sur disque?
  947.             if (ok) {
  948.               if (r->msg[0] == '\0') {
  949.                 strcpy(r->msg,"Cache Read Error : Unexpected error");
  950.               }
  951.             } else { // lire en mΘmoire
  952.               
  953.               if (!dataincache) {
  954.                                 /* Read in memory from cache */
  955.                                 if (flags & FETCH_BODY) {
  956.                                     if (strnotempty(previous_save)) {
  957.                                         FILE* fp = fopen(fconv(previous_save), "rb");
  958.                                         if (fp != NULL) {
  959.                                             r->adr = (char*) malloc(r->size + 4);
  960.                                             if (r->adr != NULL) {
  961.                                                 if (r->size > 0 && fread(r->adr, 1,  r->size, fp) != r->size) {
  962.                                                     r->statuscode=STATUSCODE_INVALID;
  963.                                                     sprintf(r->msg,"Read error in cache disk data: %s", strerror(errno));
  964.                                                 }
  965.                                             } else {
  966.                                                 r->statuscode=STATUSCODE_INVALID;
  967.                                                 strcpy(r->msg,"Read error (memory exhausted) from cache");
  968.                                             }
  969.                                             fclose(fp);
  970.                                         } else {
  971.                                             r->statuscode=STATUSCODE_INVALID;
  972.                                             sprintf(r->msg, "Read error (can't open '%s') from cache", fconv(previous_save));
  973.                                         }
  974.                                     } else {
  975.                                         r->statuscode=STATUSCODE_INVALID;
  976.                                         strcpy(r->msg,"Cached file name is invalid");
  977.                                     }
  978.                                 }
  979.               } else {
  980.                                 // lire fichier (d'un coup)
  981.                                 if (flags & FETCH_BODY) {
  982.                                     r->adr=(char*) malloc(r->size+1);
  983.                                     if (r->adr!=NULL) {
  984.                                         if (unzReadCurrentFile(index->zFile, r->adr, r->size) != r->size) {  // erreur
  985.                                             free(r->adr);
  986.                                             r->adr=NULL;
  987.                                             r->statuscode=STATUSCODE_INVALID;
  988.                                             strcpy(r->msg,"Cache Read Error : Read Data");
  989.                                         } else
  990.                                             *(r->adr+r->size)='\0';
  991.                                         //printf(">%s status %d\n",back[p].r->contenttype,back[p].r->statuscode);
  992.                                     } else {  // erreur
  993.                                         r->statuscode=STATUSCODE_INVALID;
  994.                                         strcpy(r->msg,"Cache Memory Error");
  995.                                     }
  996.                                 }
  997.                             }
  998.             }
  999.           }    // si save==null, ne rien charger (juste en tΩte)
  1000.         } else {
  1001.           r->statuscode=STATUSCODE_INVALID;
  1002.           strcpy(r->msg,"Cache Read Error : Read Header Data");
  1003.         }
  1004.         unzCloseCurrentFile(index->zFile);
  1005.       } else {
  1006.         r->statuscode=STATUSCODE_INVALID;
  1007.         strcpy(r->msg,"Cache Read Error : Open File");
  1008.       }
  1009.  
  1010.     } else {
  1011.       r->statuscode=STATUSCODE_INVALID;
  1012.       strcpy(r->msg,"Cache Read Error : Bad Offset");
  1013.     }
  1014.   } else {
  1015.     r->statuscode=STATUSCODE_INVALID;
  1016.     strcpy(r->msg,"File Cache Entry Not Found");
  1017.   }
  1018.     if (r->location[0] != '\0') {
  1019.         r->location = strdup(r->location);
  1020.     } else {
  1021.         r->location = NULL;
  1022.     }
  1023.   return r;
  1024. }
  1025.  
  1026.  
  1027. /* ------------------------------------------------------------ */
  1028. /* Old HTTrack cache (dat/ndx) format                           */
  1029. /* ------------------------------------------------------------ */
  1030.  
  1031. static int cache_brstr(char* adr,char* s) {
  1032.   int i;
  1033.   int off;
  1034.   char buff[256 + 1];
  1035.   off=binput(adr,buff,256);
  1036.   adr+=off;
  1037.   sscanf(buff,"%d",&i);
  1038.   if (i>0)
  1039.     strncpy(s,adr,i);
  1040.   *(s+i)='\0';
  1041.   off+=i;
  1042.   return off;
  1043. }
  1044.  
  1045. static void cache_rstr(FILE* fp,char* s) {
  1046.   INTsys i;
  1047.   char buff[256+4];
  1048.   linput(fp,buff,256);
  1049.   sscanf(buff,INTsysP,&i);
  1050.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  1051.     i=0;
  1052.   if (i>0) {
  1053.     if ((int) fread(s,1,i,fp) != i) {
  1054.       int fread_cache_failed = 0;
  1055.       assertf(fread_cache_failed);
  1056.     }
  1057.   }
  1058.   *(s+i)='\0';
  1059. }
  1060.  
  1061. static char* cache_rstr_addr(FILE* fp) {
  1062.   INTsys i;
  1063.   char* addr = NULL;
  1064.   char buff[256+4];
  1065.   linput(fp,buff,256);
  1066.   sscanf(buff,"%d",&i);
  1067.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  1068.     i=0;
  1069.   if (i > 0) {
  1070.     addr = malloc(i + 1);
  1071.     if (addr != NULL) {
  1072.       if ((int) fread(addr,1,i,fp) != i) {
  1073.         int fread_cache_failed = 0;
  1074.         assertf(fread_cache_failed);
  1075.       }
  1076.       *(addr+i)='\0';
  1077.     }
  1078.   }
  1079.   return addr;
  1080. }
  1081.  
  1082. static void cache_rint(FILE* fp,int* i) {
  1083.   char s[256];
  1084.   cache_rstr(fp,s);
  1085.   sscanf(s,"%d",i);
  1086. }
  1087.  
  1088. static void cache_rLLint(FILE* fp,unsigned long* i) {
  1089.     int l;
  1090.   char s[256];
  1091.   cache_rstr(fp,s);
  1092.   sscanf(s,"%d",&l);
  1093.     *i = (unsigned long)l;
  1094. }
  1095.  
  1096. static int PT_LoadCache__Old(PT_Index index_, const char *filename) {
  1097.     if (index_ != NULL && filename != NULL) {
  1098.         char * pos = strrchr(filename, '.');
  1099.         PT_Index__Old cache = &index_->slots.formatOld;
  1100.         long int ndxSize;
  1101.         cache->filenameDat[0] = '\0';
  1102.         cache->filenameNdx[0] = '\0';
  1103.         cache->path[0] = '\0';
  1104.  
  1105.         {
  1106.             PT_Index__Old index = cache;
  1107.             const char * abpath;
  1108.             int slashes;
  1109.             /* -------------------- COPY OF THE __New() CODE -------------------- */
  1110.             /* Compute base path for this index - the filename MUST be absolute! */
  1111.             for(slashes = 2, abpath = filename + (int)strlen(filename) - 1 
  1112.                 ; abpath > filename && ( ( *abpath != '/'&& *abpath != '\\' ) || --slashes > 0)
  1113.                 ; abpath--);
  1114.             index->path[0] = '\0';
  1115.             if (slashes == 0 && *abpath != 0) {
  1116.                 int i;
  1117.                 strncat(index->path, filename, (int) ( abpath - filename ) + 1 );
  1118.                 for(i = 0 ; index->path[i] != 0 ; i++) {
  1119.                     if (index->path[i] == '\\') {
  1120.                         index->path[i] = '/';
  1121.                     }
  1122.                 }
  1123.             }
  1124.             /* -------------------- END OF COPY OF THE __New() CODE -------------------- */
  1125.         }
  1126.  
  1127.         /* Index/data filenames */
  1128.         if (pos != NULL) {
  1129.             int nLen = (int) (pos - filename);
  1130.             strncat(cache->filenameDat, filename, nLen);
  1131.             strncat(cache->filenameNdx, filename, nLen);
  1132.             strcat(cache->filenameDat, ".dat");
  1133.             strcat(cache->filenameNdx, ".ndx");
  1134.         }
  1135.         ndxSize = filesize(cache->filenameNdx);
  1136.         cache->timestamp = file_timestamp(cache->filenameDat);
  1137.         cache->dat = fopen(cache->filenameDat, "rb");
  1138.         cache->ndx = fopen(cache->filenameNdx, "rb");
  1139.         if (cache->dat != NULL && cache->ndx != NULL && ndxSize > 0) {
  1140.             char * use = malloc(ndxSize + 1);
  1141.             if (fread(use, 1, ndxSize, cache->ndx) == ndxSize) {
  1142.                 char firstline[256];
  1143.                 char* a=use;
  1144.                 use[ndxSize] = '\0';
  1145.                 a += cache_brstr(a, firstline);
  1146.                 if (strncmp(firstline,"CACHE-",6)==0) {       // Nouvelle version du cache
  1147.                     if (strncmp(firstline,"CACHE-1.",8)==0) {      // Version 1.1x
  1148.                         cache->version=(int)(firstline[8]-'0');           // cache 1.x
  1149.                         if (cache->version <= 5) {
  1150.                             a+=cache_brstr(a,firstline);
  1151.                             strcpy(cache->lastmodified,firstline);
  1152.                         } else {
  1153.                             // fprintf(opt->errlog,"Cache: version 1.%d not supported, ignoring current cache"LF,cache->version);
  1154.                             fclose(cache->dat);
  1155.                             cache->dat=NULL;
  1156.                             free(use);
  1157.                             use=NULL;
  1158.                         }
  1159.                     } else {        // non supportΘ
  1160.                         // fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: %s not supported, ignoring current cache"LF,firstline);
  1161.                         fclose(cache->dat);
  1162.                         cache->dat=NULL;
  1163.                         free(use);
  1164.                         use=NULL;
  1165.                     }
  1166.                     /* */
  1167.                 } else {              // Vieille version du cache
  1168.                     /* */
  1169.                     // fspc(opt->log,"warning"); fprintf(opt->log,"Cache: importing old cache format"LF);
  1170.                     cache->version=0;        // cache 1.0
  1171.                     strcpy(cache->lastmodified,firstline); 
  1172.                 }
  1173.  
  1174.                 /* Create hash table for the cache (MUCH FASTER!) */
  1175.                 if (use) {
  1176.                     char line[HTS_URLMAXSIZE*2];
  1177.                     char linepos[256];
  1178.                     int  pos;
  1179.                     int firstSeen = 0;
  1180.                     while ( (a!=NULL) && (a < (use + ndxSize) ) ) {
  1181.                         a=strchr(a+1,'\n');     /* start of line */
  1182.                         if (a) {
  1183.                             a++;
  1184.                             /* read "host/file" */
  1185.                             a+=binput(a,line,HTS_URLMAXSIZE);
  1186.                             a+=binput(a,line+strlen(line),HTS_URLMAXSIZE);
  1187.                             /* read position */
  1188.                             a+=binput(a,linepos,200);
  1189.                             sscanf(linepos,"%d",&pos);
  1190.  
  1191.                             /* Add entry */
  1192.                             inthash_add(cache->hash,line,pos);
  1193.  
  1194.                             /* First link as starting URL */
  1195.                             if (!firstSeen) {
  1196.                                 if (strstr(line, "/robots.txt") == NULL) {
  1197.                                     PT_Index__Old index = cache;
  1198.                                     firstSeen = 1;
  1199.                                     if (!link_has_authority(line))
  1200.                                         strcat(index->startUrl, "http://");
  1201.                                     strcat(index->startUrl, line);
  1202.                                 }
  1203.                             }
  1204.  
  1205.                         }
  1206.                     }
  1207.                     /* Not needed anymore! */
  1208.                     free(use);
  1209.                     use=NULL;
  1210.                     return 1;
  1211.                 }
  1212.             }
  1213.         }
  1214.     }
  1215.     return 0;
  1216. }
  1217.  
  1218. static String DecodeUrl(const char * url) {
  1219.     int i;
  1220.     String s = STRING_EMPTY;
  1221.     StringClear(s);
  1222.     for(i = 0 ; url[i] != '\0' ; i++) {
  1223.         if (url[i] == '+') {
  1224.             StringAddchar(s, ' ');
  1225.         } else if (url[i] == '%') {
  1226.             if (url[i + 1] == '%') {
  1227.                 StringAddchar(s, '%');
  1228.                 i++;
  1229.             } else if (url[i + 1] != 0 && url[i + 2] != 0) {
  1230.                 char tmp[3];
  1231.                 int codepoint = 0;
  1232.                 tmp[0] = url[i + 1];
  1233.                 tmp[1] = url[i + 2];
  1234.                 tmp[2] = 0;
  1235.                 if (sscanf(tmp, "%x", &codepoint) == 1) {
  1236.                     StringAddchar(s, (char)codepoint);
  1237.                 }
  1238.                 i += 2;
  1239.             }
  1240.         } else {
  1241.             StringAddchar(s, url[i]);
  1242.         }
  1243.     }
  1244.     return s;
  1245. }
  1246.  
  1247. static PT_Element PT_ReadCache__Old(PT_Index index, const char* url, int flags) {
  1248.     PT_Element retCode;
  1249.     MutexLock(&index->slots.formatOld.fileLock);
  1250.     {
  1251.         retCode = PT_ReadCache__Old_u(index, url, flags);
  1252.     }
  1253.     MutexUnlock(&index->slots.formatOld.fileLock);
  1254.     return retCode;
  1255. }
  1256.  
  1257. static PT_Element PT_ReadCache__Old_u(PT_Index index_, const char* url, int flags) {
  1258.     PT_Index__Old cache = (PT_Index__Old) &index_->slots.formatOld;
  1259.   long int hash_pos;
  1260.   int hash_pos_return;
  1261.   char location_default[HTS_URLMAXSIZE*2];
  1262.   char previous_save[HTS_URLMAXSIZE*2];
  1263.   char previous_save_[HTS_URLMAXSIZE*2];
  1264.   PT_Element r;
  1265.   int ok=0;
  1266.  
  1267.     if (cache == NULL || cache->hash == NULL || url == NULL || *url == 0)
  1268.         return NULL;
  1269.     if ((r = PT_ElementNew()) == NULL)
  1270.         return NULL;
  1271.     location_default[0] = '\0';
  1272.     previous_save[0] = previous_save_[0] = '\0';
  1273.   memset(r, 0, sizeof(_PT_Element));
  1274.   r->location = location_default;
  1275.     strcpy(r->location, ""); 
  1276.     if (strncmp(url, "http://", 7) == 0)
  1277.         url += 7;
  1278.   hash_pos_return=inthash_read(cache->hash, url, (long int*)&hash_pos);
  1279.  
  1280.   if (hash_pos_return) {
  1281.     int pos = (int) hash_pos;     /* simply */
  1282.  
  1283.     if (fseek(cache->dat, (pos>0) ? pos : (-pos), SEEK_SET) == 0) {
  1284.             /* Importer cache1.0 */
  1285.             if (cache->version==0) {
  1286.                 OLD_htsblk old_r;
  1287.                 if (fread((char*) &old_r,1,sizeof(old_r),cache->dat) == sizeof(old_r)) { // lire tout (y compris statuscode etc)
  1288.                     int i;
  1289.                     String urlDecoded;
  1290.                     r->statuscode = old_r.statuscode;
  1291.                     r->size = old_r.size;        // taille fichier
  1292.                     strcpy(r->msg, old_r.msg);
  1293.                     strcpy(r->contenttype, old_r.contenttype);
  1294.  
  1295.                     /* Guess the destination filename.. this sucks, because this method is not reliable.
  1296.                         Yes, the old 1.0 cache format was *that* bogus. /rx */
  1297. #define FORBIDDEN_CHAR(c) (c == '~' \
  1298.     || c == '\\' \
  1299.     || c == ':' \
  1300.     || c == '*' \
  1301.     || c == '?' \
  1302.     || c == '\"' \
  1303.     || c == '<' \
  1304.     || c == '>' \
  1305.     || c == '|' \
  1306.     || c == '@' \
  1307.     || ((unsigned char) c ) <= 31 \
  1308.     || ((unsigned char) c ) == 127 \
  1309.     )
  1310.                     urlDecoded = DecodeUrl(jump_protocol_and_auth(url));
  1311.                     strcpy(previous_save_, StringBuff(urlDecoded));
  1312.                     StringFree(urlDecoded);
  1313.                     for(i = 0 ; previous_save_[i] != '\0' && previous_save_[i] != '?' ; i++) {
  1314.                         if (FORBIDDEN_CHAR(previous_save_[i])) {
  1315.                             previous_save_[i] = '_';
  1316.                         }
  1317.                     }
  1318.                     previous_save_[i] = '\0';
  1319. #undef FORBIDDEN_CHAR
  1320.                 ok = 1;     /* import  ok */
  1321.             }
  1322.       /* */
  1323.       /* Cache 1.1 */
  1324.       } else {
  1325.         char check[256];
  1326.         unsigned long size_read;
  1327.         check[0]='\0';
  1328.         //
  1329.         cache_rint(cache->dat,&r->statuscode);
  1330.         cache_rLLint(cache->dat,&r->size);
  1331.         cache_rstr(cache->dat,r->msg);
  1332.         cache_rstr(cache->dat,r->contenttype);
  1333.         if (cache->version >= 3)
  1334.           cache_rstr(cache->dat,r->charset);
  1335.         cache_rstr(cache->dat,r->lastmodified);
  1336.         cache_rstr(cache->dat,r->etag);
  1337.         cache_rstr(cache->dat,r->location);
  1338.         if (cache->version >= 2)
  1339.           cache_rstr(cache->dat,r->cdispo);
  1340.         if (cache->version >= 4) {
  1341.           cache_rstr(cache->dat, previous_save_);  // adr
  1342.           cache_rstr(cache->dat, previous_save_);  // fil
  1343.           previous_save[0] = '\0';
  1344.           cache_rstr(cache->dat, previous_save_);  // save
  1345.         }
  1346.         if (cache->version >= 5) {
  1347.           r->headers = cache_rstr_addr(cache->dat);
  1348.         }
  1349.         //
  1350.         cache_rstr(cache->dat,check);
  1351.         if (strcmp(check,"HTS")==0) {           /* intΘgritΘ OK */
  1352.           ok=1;
  1353.         }
  1354.         cache_rLLint(cache->dat, &size_read);       /* lire size pour Ωtre s√r de la taille dΘclarΘe (rΘΘcrire) */
  1355.         if (size_read > 0) {                         /* si inscrite ici */
  1356.           r->size = size_read;
  1357.         } else {                              /* pas de donnΘes directement dans le cache, fichier prΘsent? */
  1358.                     r->size = 0;
  1359.         }
  1360.       }
  1361.  
  1362.             /* Check destination filename */
  1363.  
  1364.             {
  1365.                 PT_Index__Old index = cache;
  1366.                 /* -------------------- COPY OF THE __New() CODE -------------------- */
  1367.                 if (previous_save_[0] != '\0') {
  1368.                     int pathLen = (int) strlen(index->path);
  1369.                     if (pathLen > 0 && strncmp(previous_save_, index->path, pathLen) == 0) {            // old (<3.40) buggy format
  1370.                         strcpy(previous_save, previous_save_);
  1371.                     }
  1372.                     // relative ? (hack)
  1373.                     else if (index->safeCache
  1374.                         || (previous_save_[0] != '/'                                                                    // /home/foo/bar.gif
  1375.                         && ( !isalpha(previous_save_[0]) || previous_save_[1] != ':' ) )    // c:/home/foo/bar.gif
  1376.                         )
  1377.                     {
  1378.                         index->safeCache = 1;
  1379.                         sprintf(previous_save, "%s%s", index->path, previous_save_);
  1380.                     }
  1381.                     // bogus format (includes buggy absolute path)
  1382.                     else {
  1383.                         /* guess previous path */
  1384.                         if (index->fixedPath == 0) {
  1385.                             const char * start = jump_protocol_and_auth(url);
  1386.                             const char * end = start ? strchr(start, '/') : NULL;
  1387.                             int len = (int) (end - start);
  1388.                             if (start != NULL && end != NULL && len > 0 && len < 128) {
  1389.                                 char piece[128 + 2];
  1390.                                 const char * where;
  1391.                                 piece[0] = '\0';
  1392.                                 strncat(piece, start, len);
  1393.                                 if ((where = strstr(previous_save_, piece)) != NULL) {
  1394.                                     index->fixedPath = (int) (where - previous_save_);        // offset to relative path
  1395.                                 }
  1396.                             }
  1397.                         }
  1398.                         if (index->fixedPath > 0) {
  1399.                             int saveLen = (int) strlen(previous_save_);
  1400.                             if (index->fixedPath < saveLen) {
  1401.                                 sprintf(previous_save, "%s%s", index->path, previous_save_ + index->fixedPath);
  1402.                             } else {
  1403.                                 sprintf(r->msg, "Bogus fixePath prefix for %s (prefixLen=%d)", previous_save_, (int)index->fixedPath);
  1404.                                 r->statuscode = STATUSCODE_INVALID;
  1405.                             }
  1406.                         } else {
  1407.                             sprintf(previous_save, "%s%s", index->path, previous_save_);
  1408.                         }
  1409.                     }
  1410.                 }
  1411.                 /* -------------------- END OF COPY OF THE __New() CODE -------------------- */
  1412.             }
  1413.  
  1414.       /* Read data */
  1415.             if (ok) {
  1416.                 r->adr = NULL;
  1417.                 if ( (r->statuscode>=0) && (r->statuscode<=999)) {
  1418.                     r->adr = NULL;
  1419.                     if (pos<0) {
  1420.                         if (flags & FETCH_BODY) {
  1421.                             FILE* fp = fopen(previous_save, "rb");
  1422.                             if (fp != NULL) {
  1423.                                 r->adr = (char*) malloc(r->size + 1);
  1424.                                 if (r->adr != NULL) {
  1425.                                     if (r->size > 0 && fread(r->adr, 1, r->size, fp) != r->size) {
  1426.                                         r->statuscode=STATUSCODE_INVALID;
  1427.                                         strcpy(r->msg,"Read error in cache disk data");
  1428.                                     }
  1429.                                     r->adr[r->size] = '\0';
  1430.                                 } else {
  1431.                                     r->statuscode=STATUSCODE_INVALID;
  1432.                                     strcpy(r->msg,"Read error (memory exhausted) from cache");
  1433.                                 }
  1434.                                 fclose(fp);
  1435.                             } else {
  1436.                                 r->statuscode = STATUSCODE_INVALID;
  1437.                                 strcpy(r->msg, "Previous cache file not found (2)");
  1438.                             }
  1439.                         }
  1440.                     } else {
  1441.                         // lire fichier (d'un coup)
  1442.                         if (flags & FETCH_BODY) {
  1443.                             r->adr=(char*) malloc(r->size + 1);
  1444.                             if (r->adr!=NULL) {
  1445.                                 if (fread(r->adr, 1, r->size,cache->dat) != r->size) {  // erreur
  1446.                                     free(r->adr);
  1447.                                     r->adr=NULL;
  1448.                                     r->statuscode=STATUSCODE_INVALID;
  1449.                                     strcpy(r->msg,"Cache Read Error : Read Data");
  1450.                                 } else
  1451.                                     r->adr[r->size] = '\0';
  1452.                             } else {  // erreur
  1453.                                 r->statuscode=STATUSCODE_INVALID;
  1454.                                 strcpy(r->msg,"Cache Memory Error");
  1455.                             }
  1456.                         }
  1457.                     }
  1458.                 } else {
  1459.           r->statuscode=STATUSCODE_INVALID;
  1460.           strcpy(r->msg,"Cache Read Error : Bad Data");
  1461.         }
  1462.       } else {  // erreur
  1463.         r->statuscode=STATUSCODE_INVALID;
  1464.         strcpy(r->msg,"Cache Read Error : Read Header");
  1465.       }
  1466.     } else {
  1467.       r->statuscode=STATUSCODE_INVALID;
  1468.       strcpy(r->msg,"Cache Read Error : Seek Failed");
  1469.     }
  1470.   } else {
  1471.     r->statuscode=STATUSCODE_INVALID;
  1472.     strcpy(r->msg,"File Cache Entry Not Found");
  1473.   }
  1474.     if (r->location[0] != '\0') {
  1475.         r->location = strdup(r->location);
  1476.     } else {
  1477.         r->location = NULL;
  1478.     }
  1479.   return r;
  1480. }
  1481.  
  1482. static int PT_LookupCache__Old(PT_Index index, const char* url) {
  1483.     int retCode;
  1484.     MutexLock(&index->slots.formatOld.fileLock);
  1485.     {
  1486.         retCode = PT_LookupCache__Old_u(index, url);
  1487.     }
  1488.     MutexUnlock(&index->slots.formatOld.fileLock);
  1489.     return retCode;
  1490. }
  1491.  
  1492. static int PT_LookupCache__Old_u(PT_Index index_, const char* url) {
  1493.     if (index_ != NULL) {
  1494.         PT_Index__New cache = (PT_Index__New) &index_->slots.formatNew;
  1495.         if (cache == NULL || cache->hash == NULL || url == NULL || *url == 0)
  1496.             return 0;
  1497.         if (strncmp(url, "http://", 7) == 0)
  1498.             url += 7;
  1499.         if (inthash_read(cache->hash, url, NULL))
  1500.             return 1;
  1501.     }
  1502.     return 0;
  1503. }
  1504.  
  1505.